/*
 * OsgScene.cpp
 *
 *      Author: Etienne Bosse
 */

#include "OsgProject.h"



#include <gmtl/Vec.h>
#include <gmtl/Coord.h>
#include <gmtl/Xforms.h>
#include <gmtl/Math.h>

#include <string>
#include <iostream>
#include <stdlib.h>

OsgProject::OsgProject(vrj::Kernel* kern, int& argc, char** argv) : vrj::OsgApp(kern)
{
	// On initialise la wand et la head
	_deviceManager = new CDeviceManager();

	// On initialise les noeud personne
	_login = new CLogon(-2.5,5.5,-5,"./ressource/connection.png",1,0.5f);
	_logout = new CLogon(-2.5,5.5,-5,"./ressource/SignalLost.png",1,0.5f);
#if CAVE == 0
	_snowGenerator = new CSnowGenerator(1.0f,300,8,1,10,10);
#endif
	_joueur = new CJoueur(0,-20,0,3.0,0.5);
	_skybox = new CSkyBox();
	_map = new CMapNode(_joueur,_skybox);
	_bombe = new osg::Group;
	_bombManager = new CBombManager(_map,_joueur,_bombe,GL_LIGHTING);
	_arm = new CArm(GL_LIGHTING);

#if CAVE == 1
	_hud = new Chud(800, 800);
#endif

	// On rajoute les modèle sur la map
	// Les arbres
	_map->addElementOnMap(-98.0f,70.0f,MODEL_TREE);
	_map->addElementOnMap(-74.0f,68.0f,MODEL_TREE);
	_map->addElementOnMap(-88.0f,64.0f,MODEL_TREE);
	_map->addElementOnMap(-44.0f,84.0f,MODEL_TREE);
	_map->addElementOnMap(-40.0f,59.0f,MODEL_TREE);
	_map->addElementOnMap(-32.0f,72.0f,MODEL_TREE);
	_map->addElementOnMap(-18.0f,87.0f,MODEL_TREE);
	_map->addElementOnMap(75.0f,60.0f,MODEL_TREE);
	_map->addElementOnMap(64.0f,74.0f,MODEL_TREE);
	_map->addElementOnMap(50.0f,86.0f,MODEL_TREE);
	_map->addElementOnMap(37.0f,79.0f,MODEL_TREE);
	_map->addElementOnMap(20.0f,55.0f,MODEL_TREE);
	_map->addElementOnMap(15.0f,66.0f,MODEL_TREE);
	_map->addElementOnMap(-55.0f,-15.0f,MODEL_TREE);
	_map->addElementOnMap(-20.0f,27.0f,MODEL_TREE);
	_map->addElementOnMap(14.0f,-40.0f,MODEL_TREE);
	_map->addElementOnMap(28.0f,5.0f,MODEL_TREE);
	_map->addElementOnMap(70.0f,45.0f,MODEL_TREE);
	_map->addElementOnMap(49.0f,-30.0f,MODEL_TREE);

	_map->addElementOnMap(20.0f,-44.0f,MODEL_TREE);
	_map->addElementOnMap(15.0f,-50.0f,MODEL_TREE);
	_map->addElementOnMap(-55.0f,-40.0f,MODEL_TREE);
	_map->addElementOnMap(-54.0f,-39.0f,MODEL_TREE);
	_map->addElementOnMap(14.0f,-60.0f,MODEL_TREE);
	_map->addElementOnMap(28.0f,-65.0f,MODEL_TREE);
	_map->addElementOnMap(70.0f,-80.0f,MODEL_TREE);
	_map->addElementOnMap(28.0f,-65.0f,MODEL_TREE);
	_map->addElementOnMap(-70.0f,-57.0f,MODEL_TREE);
	_map->addElementOnMap(-49.0f,-72.0f,MODEL_TREE);
	_map->addElementOnMap(-13.0f,-70.0f,MODEL_TREE);
	// Les rochets
	_map->addElementOnMap(54.0793f,-36.2248f,MODEL_ROCK);
	_map->addElementOnMap(-88.0f,-60.0f,MODEL_ROCK);
	_map->addElementOnMap(-44.0f,60.0f,MODEL_ROCK);
	_map->addElementOnMap(-30.0f,-1.0f,MODEL_ROCK);
	_map->addElementOnMap(-60.0f,-10.0f,MODEL_ROCK);
	_map->addElementOnMap(-15.0f,24.0f,MODEL_ROCK);
	_map->addElementOnMap(11.0f,-44.0f,MODEL_ROCK);
	_map->addElementOnMap(25.0f,10.0f,MODEL_ROCK);
	_map->addElementOnMap(77.0f,50.0f,MODEL_ROCK);
	_map->addElementOnMap(44.0f,-30.0f,MODEL_ROCK);

	// Le chalet
	_map->addElementOnMap(1.0f,-20.0f,MODEL_CHALET);


	//initialisation de l'angle
	theta = 0.0f;

	// initialisation pour les variables d'effets
	_useBloom = true;
	_typeBloom = 0;
	_flashTimeMax = 2.7f;
	_flashTime = _flashTimeMax;
	_flashValue = 0.0;
	_flashStep = 0;

	_distortionTimeMax = 0.5f;
	_distortionTime = _distortionTimeMax;
	_distortionStep = 0;

	// Initialisation des états des boutons
	_button1StateUsed = false;
	_button2StateUsed = false;
	_button3StateUsed = false;

	// Initialisation des états du jeu
	_step0TimeMax = 4.0;
	_gameStep = 0;
	_stepTimeElapsed = 0;

	// Initialisation des variables de step de jeu 1
	_timeDistort = 21;
	_bombeTimeMax = 110;
	_bombeTimer = 0;
	_bombeExplose = false;
	_popBomb = true;
	_bombPoped = false;
	_bombDiffused = false;
	_bombGrabbed = false;
	_bombDiffuse = 0;
	_bombNum = 5;
}

void OsgProject::initScene()
{
	//Initialisation du noeud principal
	mRootNode = new osg::Group();

	// On crée les lumiere
	_lightSource1 = new osg::LightSource();
	_lightSource1->setLight(new osg::Light());
	_lightSource1->getLight()->setDiffuse(osg::Vec4(1.0f,0.96862f,0.8470f,1.0f));
	_lightSource1->getLight()->setSpecular(osg::Vec4(1.0f,0.96862f,0.8470f,1.0f));
	_lightSource1->getLight()->setAmbient(osg::Vec4(0.0f,0.0f,0.0f,1.0f));
	_lightSource1->getLight()->setPosition(osg::Vec4(0.0f,5.0f,0.0f,0.0f));
	_lightSource1->getLight()->setDirection(osg::Vec3(-0.0f,-1.0f,0.0f));

	osg::StateSet *stateset = mRootNode->getOrCreateStateSet();
	_lightSource1->setStateSetModes(*stateset,osg::StateAttribute::ON);



	// On initialise les boutons
	_deviceManager->init();
	// On initialise la wand et certain de ses bouton
	std::string but0("VJButton0");
	std::string but1("VJButton1");
	std::string but2("VJButton2");
	_deviceManager->addButton(but0);
	_deviceManager->addButton(but1);
	_deviceManager->addButton(but2);
}

void OsgProject::bufferPreDraw()
{
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClear(GL_COLOR_BUFFER_BIT);
}


void OsgProject::preFrame()
{
	float delta = _deviceManager->getDeltaTime();
	_deltaTime = delta;

	_deviceManager->updateDevices(getDrawScaleFactor()); // On met à jours les devices

	stepManagment(((delta<1)?delta:0)); // On gere les step

	int mov = 0;
	// On gère les états des boutons
	if(_deviceManager->getButton(0)->isClicked()==true)
	{
		if(_button1StateUsed==false)
		{
			_button1StateUsed = true;
		}
		if(_gameStep==1)
		{
			_joueur->forward(delta);
			mov =1;
		}
		if(_gameStep==2)
		{
			 std::exit(1);
		}

	}
	else if( _deviceManager->getButton(0)->isClicked()==false )
	{
		_button1StateUsed = false;
	}
	if(_deviceManager->getButton(1)->isClicked()==true)
	{
		if(_button3StateUsed==false)
		{
			_button3StateUsed = true;
		}
		if(_gameStep==1)
		{
			_joueur->turnLeft(delta);
		}

	}
	else if( _deviceManager->getButton(1)->isClicked()==false )
	{
		_button3StateUsed = false;
	}
	if(_deviceManager->getButton(2)->isClicked()==true)
	{
		if(_button2StateUsed==false)
		{
			_button2StateUsed = true;
		}
		if(_gameStep==1)
		{
			_joueur->turnRight(delta);
		}
	}
	else if( _deviceManager->getButton(2)->isClicked()==false )
	{
		_button2StateUsed = false;
	}

	// On update le gameplay
	if(_gameStep==1)
	{
		if(_bombeExplose)
		{
			_bombManager->update(delta,osg::Vec3(0.0f,0.0f,0.0f),_deviceManager->getWandPosition(),_deviceManager->getHeadPosition());
		}

		if(_bombPoped==false && _bombeExplose == false && _bombDiffuse<_bombNum)
		{
			_bombeTimer = 0;
			_bombGrabbed = false;
			_bombPoped = true;
			_bombManager->addBomb();
			_deviceManager->stopRecordWandMovement();
		}

//		std::cout << "La position de la wand:"<< std::endl;
//		std::cout << "X= :"<< _joueur->getVirtual3Position().x()<< std::endl;
//		std::cout << "Y= :"<< _joueur->getVirtual3Position().y()<< std::endl;
//		std::cout << "Z= :"<< _joueur->getVirtual3Position().z()<< std::endl;


		// On check si on choppe la bombe
		if(_bombPoped && _bombeExplose == false)
		{
			_bombeTimer += delta;
			if(_bombManager->checkIntersect(_deviceManager->getWandPosition(),_deviceManager->getHeadPosition())&& _bombGrabbed == false)
			{
				_bombGrabbed = true;
				_bombManager->grabBomb(_deviceManager->getWandPosition());
				_deviceManager->startRecordWandMovement();
			}
			if(_bombGrabbed)
			{
				_bombManager->update(delta,_deviceManager->getWandMovement(),_deviceManager->getWandPosition(),_deviceManager->getHeadPosition());
				if(_bombManager->checkDiffusable(_deviceManager->getWandPosition(),_deviceManager->getHeadPosition()))
				{
					_bombDiffused = true;
					removeBomb();
				}
			}
			if(_bombDiffused)
			{
				_bombPoped = false;
				_bombDiffuse++;
				if(_bombDiffuse<_bombNum)
				{
					_bombeTimer = 0;
					_bombPoped = true;
					_bombManager->addBomb();
					_deviceManager->stopRecordWandMovement();
				}
				_bombGrabbed = false;
				_bombDiffused = false;

			}
		}

	}

	// On update les noeuds perso
	gmtl::Vec3f hp;
	osg::Vec3f ohp = _deviceManager->getHeadPosition();
	hp.set(ohp._v[0],ohp._v[1],ohp._v[2]);
	if(_gameStep==0)
	{
		_login->update(delta);
	}
	else if(_gameStep==2)
	{
		_logout->update(delta);
	}
	else if(_gameStep==1)
	{
#if CAVE == 0
		_snowGenerator->update(delta,hp,_joueur->getSpeed()/3.5,mov);
#endif
		_map->update(delta);
		_hud->update(_bombNum, _bombDiffuse, _bombeTimer, _bombeTimeMax,((_bombDiffuse==_bombNum)?true:false),delta);
		_arm->updatePosition(_deviceManager->getHeadPosition());
	}

	//mNavigator.update(fDeltaTime);
}

void OsgProject::latePreFrame()
{
	   gmtl::Matrix44f world_transform;
	   //gmtl::invertFull(world_transform, mNavigator.getCurPos());
	   // Update the scene graph
	   osg::Matrix osg_current_matrix;
	   osg_current_matrix.set(world_transform.getData());

	   // Finish updating the scene graph.
	   vrj::OsgApp::latePreFrame();
}

#if CAVE == 0
void OsgProject::draw()
{
	glClear(GL_DEPTH_BUFFER_BIT);

	// Users have reported problems with OpenGL reporting stack underflow
	// problems when the texture attribute bit is pushed here, so we push all
	// attributes *except* GL_TEXTURE_BIT.
	glPushAttrib(GL_ALL_ATTRIB_BITS & ~GL_TEXTURE_BIT);
	glPushAttrib(GL_TRANSFORM_BIT);
	glPushAttrib(GL_VIEWPORT_BIT);

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();

	osg::ref_ptr<osgUtil::SceneView> sv;
	sv = (*sceneViewer);    // Get context specific scene viewer
	vprASSERT(sv.get() != NULL);

	// The OpenGL Draw Manager that we are rendering for.
	//Get the view matrix and the frustrum form the draw manager
	GlDrawManager* gl_manager =
	   dynamic_cast<GlDrawManager*>(this->getDrawManager());
	vprASSERT(gl_manager != NULL);
	GlUserData* user_data = gl_manager->currentUserData();

	// Set the up the viewport (since OSG clears it out)
	float vp_ox, vp_oy, vp_sx, vp_sy;   // The float vrj sizes of the view ports
	int w_ox, w_oy, w_width, w_height;  // Origin and size of the window
	user_data->getViewport()->getOriginAndSize(vp_ox, vp_oy, vp_sx, vp_sy);
	user_data->getGlWindow()->getOriginSize(w_ox, w_oy, w_width, w_height);

	// compute unsigned versions of the viewport info (for passing to glViewport)
	const unsigned int ll_x =
	   static_cast<unsigned int>(vp_ox * static_cast<float>(w_width));
	const unsigned int ll_y =
	   static_cast<unsigned int>(vp_oy * static_cast<float>(w_height));
	const unsigned int x_size =
	   static_cast<unsigned int>(vp_sx * static_cast<float>(w_width));
	const unsigned int y_size =
	   static_cast<unsigned int>(vp_sy * static_cast<float>(w_height));

	//sv->setCalcNearFar(false);
	sv->setComputeNearFarMode(osgUtil::CullVisitor::DO_NOT_COMPUTE_NEAR_FAR);
	sv->setViewport(ll_x, ll_y, x_size, y_size);

	//Get the frustrum
	Projection* project = user_data->getProjection();
	Frustum frustum = project->getFrustum();
	sv->setProjectionMatrixAsFrustum(frustum[Frustum::VJ_LEFT],
									 frustum[Frustum::VJ_RIGHT],
									 frustum[Frustum::VJ_BOTTOM],
									 frustum[Frustum::VJ_TOP],
									 frustum[Frustum::VJ_NEAR],
									 frustum[Frustum::VJ_FAR]);

	// Copy the view matrix
	sv->setViewMatrix(osg::Matrix(project->getViewMatrix().mData));

	//Draw the scene
	// NOTE: It is not safe to call osgUtil::SceneView::update() here; it
	// should only be called by a single thread. The equivalent of calling
	// osgUtil::SceneView::update() is in vrj::OsgApp::update().
	sv->cull();



	// On effectue le rendu normal dans le fboscreen
	GLuint id = 0;
	_fboScreen.BeginUse();
	{
		sv->draw();
	}
	_fboScreen.EndUse();


	// On applique les filtres post rendu
	// Distortion de l'image
	generateDistortionEffect(_deltaTime);

	// On met l'effet de flash
	generateFlashEffect(_deltaTime);

	// Création du bloom effect
	if(_useBloom)
	{
		generateBloomEffect();
	}

	id = 0;
	// On ajoute le bloom effect
	_shaderAddEffect.StartUse();
	{
		// On passe la texture de rendu normal
		_fboScreen.BindTexture(id);
		_shaderAddEffect.UniformTexture("texScreen",id++);
		_shaderAddEffect.Uniform("useBloom", _useBloom);
		_shaderAddEffect.Uniform("flashValue",_flashValue);
		_shaderAddEffect.Uniform("typeBloom",_typeBloom);

		// On passe la/les texture de bloom
		if(_useBloom)
		{
			if(_typeBloom==0)
			{
				_fboBloom1.BindTexture(id);
				_shaderAddEffect.UniformTexture("textBloom1",id++);

				_fboBloom2.BindTexture(id);
				_shaderAddEffect.UniformTexture("textBloom2",id++);

				_fboBloom3.BindTexture(id);
				_shaderAddEffect.UniformTexture("textBloom3",id++);

				_fboBloom4.BindTexture(id);
				_shaderAddEffect.UniformTexture("textBloom4",id++);
			}
			else if(_typeBloom == 1)
			{
				_fboBloom1.BindTexture(id);
				_shaderAddEffect.UniformTexture("textBloom1",id++);
			}
		}

		// On effectue le rendu final
		fakeRenderForShader();

		if(_useBloom)
		{
			if(_typeBloom==0)
			{
				_fboBloom4.UnbindTexture(--id);
				_fboBloom3.UnbindTexture(--id);
				_fboBloom2.UnbindTexture(--id);
				_fboBloom1.UnbindTexture(--id);
			}
			else if(_typeBloom == 1)
			{
				_fboBloom1.UnbindTexture(--id);
			}
		}
		_fboScreen.UnbindTexture(--id);
	}
	_shaderAddEffect.EndUse();

	glMatrixMode(GL_PROJECTION);
	glPopMatrix();

	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();

	glPopAttrib();
	glPopAttrib();
	glPopAttrib();

}
#endif
/**
 * Rendu d'une texture sur un quad qui prend tout l'écran, afin d'appliquer des filtres sur des texture
 * et faire le rendu final
 */
void OsgProject::fakeRenderForShader()
{
	// On affiche un quad à l'écran :
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();

	// On bind la texture
	glEnable(GL_TEXTURE_2D);
	glColor3f(1.0f, 1.0f, 1.0f);

	glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f);
		glVertex2f(-1.0f, -1.0f);
		glTexCoord2f(1.0f, 0.0f);
		glVertex2f(1.0f, -1.0f);
		glTexCoord2f(1.0f, 1.0f);
		glVertex2f(1.0f, 1.0f);
		glTexCoord2f(0.0f, 1.0f);
		glVertex2f(-1.0f, 1.0f);
	glEnd();

	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();

	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
}

void OsgProject::generateBloomEffect()
{
	// Le seuillage
	_fboBloom1.BeginUse();
	{
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		_shaderLuminenceTreshold.StartUse();
		{
			_fboScreen.BindTexture(0);
			_shaderLuminenceTreshold.UniformTexture("textScreen",0);
			_shaderLuminenceTreshold.Uniform("typeBloom",_typeBloom);
			fakeRenderForShader();
			_fboScreen.UnbindTexture(0);
		}
		_shaderLuminenceTreshold.EndUse();
	}
	_fboBloom1.EndUse();

	if(_typeBloom==0)
	{
		// Le flou horizontal
		_fboBloomBlur1.BeginUse();
		{
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			_shaderBoxBlur.StartUse();
			{
				_fboBloom1.BindTexture(0);
				_shaderBoxBlur.UniformTexture("textToBlur",0);
				_shaderBoxBlur.Uniform("blur_kernel",2.0f);
				_shaderBoxBlur.Uniform("isHorizontal",true);
				_shaderBoxBlur.Uniform("textWidth",_fboBloomBlur1.getWidth());
				_shaderBoxBlur.Uniform("textHeight",_fboBloomBlur1.getHeight());
				fakeRenderForShader();
				_fboBloom1.UnbindTexture(0);
			}
			_shaderBoxBlur.EndUse();
		}
		_fboBloomBlur1.EndUse();

		// Le flou vertical
		_fboBloom1.BeginUse();
		{
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			_shaderBoxBlur.StartUse();
			{
				_fboBloomBlur1.BindTexture(0);
				_shaderBoxBlur.UniformTexture("textToBlur",0);
				_shaderBoxBlur.Uniform("blur_kernel",2.0f);
				_shaderBoxBlur.Uniform("isHorizontal",false);
				_shaderBoxBlur.Uniform("textWidth",_fboBloomBlur1.getWidth());
				_shaderBoxBlur.Uniform("textHeight",_fboBloomBlur1.getHeight());
				fakeRenderForShader();
				_fboBloomBlur1.UnbindTexture(0);
			}
			_shaderBoxBlur.EndUse();
		}
		_fboBloom1.EndUse();



		// Création de la deuxieme texture de bloom taille 1/2
		// On copie downsample le plus gros fbo
		_fboBloom2.BeginUse();
		{
			_shaderCopy.StartUse();
			{
				_fboBloom1.BindTexture(0);
				_shaderCopy.UniformTexture("textBase",0);
				fakeRenderForShader();
				_fboBloom1.UnbindTexture(0);
			}
			_shaderCopy.EndUse();
		}
		_fboBloom2.EndUse();

		// Le flou horizontal
		_fboBloomBlur2.BeginUse();
		{
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			_shaderBoxBlur.StartUse();
			{
				_fboBloom2.BindTexture(0);
				_shaderBoxBlur.UniformTexture("textToBlur",0);
				_shaderBoxBlur.Uniform("gauss_kernel",8.0f);
				_shaderBoxBlur.Uniform("isHorizontal",true);
				_shaderBoxBlur.Uniform("textWidth",_fboBloomBlur2.getWidth());
				_shaderBoxBlur.Uniform("textHeight",_fboBloomBlur2.getHeight());
				fakeRenderForShader();
				_fboBloom2.UnbindTexture(0);
			}
			_shaderBoxBlur.EndUse();
		}
		_fboBloomBlur2.EndUse();

		// Le flou vertical
		_fboBloom2.BeginUse();
		{
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			_shaderBoxBlur.StartUse();
			{
				_fboBloomBlur2.BindTexture(0);
				_shaderBoxBlur.UniformTexture("textToBlur",0);
				_shaderBoxBlur.Uniform("gauss_kernel",8.0f);
				_shaderBoxBlur.Uniform("isHorizontal",false);
				_shaderBoxBlur.Uniform("textWidth",_fboBloomBlur2.getWidth());
				_shaderBoxBlur.Uniform("textHeight",_fboBloomBlur2.getHeight());
				fakeRenderForShader();
				_fboBloomBlur2.UnbindTexture(0);
			}
			_shaderBoxBlur.EndUse();
		}
		_fboBloom2.EndUse();

		// Création de la troisieme texture de bloom taille 1/4
		// On copie downsample le plus gros fbo
		_fboBloom3.BeginUse();
		{
			_shaderCopy.StartUse();
			{
				_fboBloom1.BindTexture(0);
				_shaderCopy.UniformTexture("textBase",0);
				fakeRenderForShader();
				_fboBloom1.UnbindTexture(0);
			}
			_shaderCopy.EndUse();
		}
		_fboBloom3.EndUse();

		// Le flou horizontal
		_fboBloomBlur3.BeginUse();
		{
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			_shaderBoxBlur.StartUse();
			{
				_fboBloom3.BindTexture(0);
				_shaderBoxBlur.UniformTexture("textToBlur",0);
				_shaderBoxBlur.Uniform("gauss_kernel",8.0f);
				_shaderBoxBlur.Uniform("isHorizontal",true);
				_shaderBoxBlur.Uniform("textWidth",_fboBloomBlur3.getWidth());
				_shaderBoxBlur.Uniform("textHeight",_fboBloomBlur3.getHeight());
				fakeRenderForShader();
				_fboBloom3.UnbindTexture(0);
			}
			_shaderBoxBlur.EndUse();
		}
		_fboBloomBlur3.EndUse();

		// Le flou vertical
		_fboBloom3.BeginUse();
		{
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			_shaderBoxBlur.StartUse();
			{
				_fboBloomBlur3.BindTexture(0);
				_shaderBoxBlur.UniformTexture("textToBlur",0);
				_shaderBoxBlur.Uniform("gauss_kernel",8.0f);
				_shaderBoxBlur.Uniform("isHorizontal",false);
				_shaderBoxBlur.Uniform("textWidth",_fboBloomBlur3.getWidth());
				_shaderBoxBlur.Uniform("textHeight",_fboBloomBlur3.getHeight());
				fakeRenderForShader();
				_fboBloomBlur3.UnbindTexture(0);
			}
			_shaderBoxBlur.EndUse();
		}
		_fboBloom3.EndUse();

		// Création de la quatrieme texture de bloom taille 1/8
		// On copie downsample le plus gros fbo
		_fboBloom4.BeginUse();
		{
			_shaderCopy.StartUse();
			{
				_fboBloom1.BindTexture(0);
				_shaderCopy.UniformTexture("textBase",0);
				fakeRenderForShader();
				_fboBloom1.UnbindTexture(0);
			}
			_shaderCopy.EndUse();
		}
		_fboBloom4.EndUse();

		// Le flou horizontal
		_fboBloomBlur4.BeginUse();
		{
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			_shaderBoxBlur.StartUse();
			{
				_fboBloom4.BindTexture(0);
				_shaderBoxBlur.UniformTexture("textToBlur",0);
				_shaderBoxBlur.Uniform("blur_kernel",8.0f);
				_shaderBoxBlur.Uniform("isHorizontal",true);
				_shaderBoxBlur.Uniform("textWidth",_fboBloomBlur4.getWidth());
				_shaderBoxBlur.Uniform("textHeight",_fboBloomBlur4.getHeight());
				fakeRenderForShader();
				_fboBloom4.UnbindTexture(0);
			}
			_shaderBoxBlur.EndUse();
		}
		_fboBloomBlur4.EndUse();

		// Le flou vertical
		_fboBloom4.BeginUse();
		{
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			_shaderBoxBlur.StartUse();
			{
				_fboBloomBlur4.BindTexture(0);
				_shaderBoxBlur.UniformTexture("textToBlur",0);
				_shaderBoxBlur.Uniform("blur_kernel",8.0f);
				_shaderBoxBlur.Uniform("isHorizontal",false);
				_shaderBoxBlur.Uniform("textWidth",_fboBloomBlur4.getWidth());
				_shaderBoxBlur.Uniform("textHeight",_fboBloomBlur4.getHeight());
				fakeRenderForShader();
				_fboBloomBlur4.UnbindTexture(0);
			}
			_shaderBoxBlur.EndUse();
		}
		_fboBloom4.EndUse();
	}
	else if(_typeBloom == 1)
	{
		// Le flou horizontal
		_fboBloomBlur1.BeginUse();
		{
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			_shaderBoxBlur.StartUse();
			{
				_fboBloom1.BindTexture(0);
				_shaderBoxBlur.UniformTexture("textToBlur",0);
				_shaderBoxBlur.Uniform("blur_kernel",10.0f);
				_shaderBoxBlur.Uniform("isHorizontal",true);
				_shaderBoxBlur.Uniform("textWidth",_fboBloomBlur1.getWidth());
				_shaderBoxBlur.Uniform("textHeight",_fboBloomBlur1.getHeight());
				fakeRenderForShader();
				_fboBloom1.UnbindTexture(0);
			}
			_shaderBoxBlur.EndUse();
		}
		_fboBloomBlur1.EndUse();

		// Le flou vertical
		_fboBloom1.BeginUse();
		{
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			_shaderBoxBlur.StartUse();
			{
				_fboBloomBlur1.BindTexture(0);
				_shaderBoxBlur.UniformTexture("textToBlur",0);
				_shaderBoxBlur.Uniform("blur_kernel",10.0f);
				_shaderBoxBlur.Uniform("isHorizontal",false);
				_shaderBoxBlur.Uniform("textWidth",_fboBloomBlur1.getWidth());
				_shaderBoxBlur.Uniform("textHeight",_fboBloomBlur1.getHeight());
				fakeRenderForShader();
				_fboBloomBlur1.UnbindTexture(0);
			}
			_shaderBoxBlur.EndUse();
		}
		_fboBloom1.EndUse();
	}
}

/**
 * Méthode qui calcul la valeur de l'effet de flash
 */
void OsgProject::generateFlashEffect(float delta)
{
	// On calcul l'effet de flash
	if(_flashTime<_flashTimeMax)
	{
		if(_flashValue>=1.0f)
		{
			_flashStep = 1;
			_flashTime = 0.0f;
		}
		if(_flashStep==0)
		{
			float v = log((_flashTime/_flashTimeMax)+0.85);
			_flashValue =  1 - ( v / log(0.85) );
			_flashTime += delta;
		}
		else if (_flashStep==1)
		{
			float v = log((_flashTime/_flashTimeMax)+0.2)/log(2);
			_flashValue =  ( v / (log(0.2)/log(2)) );
			_flashTime += delta;
		}

		// On utilise un fbo qui sera utilisé plus tard
		_fboBloom1.BeginUse();
		{
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			_shaderCopy.StartUse();
			{
				_fboScreen.BindTexture(0);
				_shaderCopy.UniformTexture("textBase",0);
				fakeRenderForShader();
				_fboScreen.UnbindTexture(0);
			}
			_shaderCopy.EndUse();
		}
		_fboBloom1.EndUse();

		_fboScreen.BeginUse();
		{
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			_shaderFlash.StartUse();
			{
				_fboBloom1.BindTexture(0);
				_shaderFlash.UniformTexture("textBase",0);
				_shaderFlash.Uniform("flashValue",_flashValue);
				fakeRenderForShader();
				_fboBloom1.UnbindTexture(0);
			}
			_shaderFlash.EndUse();
		}
		_fboScreen.EndUse();

	}
	else
	{
		_flashValue = 0.0;
	}

}

/**
 * Appelé avant tout effet
 */
void OsgProject::generateDistortionEffect(float delta)
{
	if(_distortionTime<_distortionTimeMax)
	{
		// On utilise un fbo qui sera utilisé plus tard
		_fboBloom1.BeginUse();
		{
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			_shaderCopy.StartUse();
			{
				_fboScreen.BindTexture(0);
				_shaderCopy.UniformTexture("textBase",0);
				fakeRenderForShader();
				_fboScreen.UnbindTexture(0);
			}
			_shaderCopy.EndUse();
		}
		_fboBloom1.EndUse();

		_fboScreen.BeginUse();
		{
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			_shaderDistortion.StartUse();
			{
				_fboBloom1.BindTexture(0);
				_shaderDistortion.UniformTexture("textBase",0);
				_shaderDistortion.Uniform("distortionValue",_distortionValue);
				fakeRenderForShader();
				_fboBloom1.UnbindTexture(0);
			}
			_shaderDistortion.EndUse();
		}
		_fboScreen.EndUse();

		_distortionTime += delta;

		if(_distortionStep==0)
		{
			_distortionValue = _distortionTime/_distortionTimeMax;
			if(_distortionTime>=_distortionTimeMax)
			{
				_distortionTime = 0;
				_distortionStep = 1;
			}
		}
		else if(_distortionStep==1)
		{
			_distortionValue = 1 - _distortionTime/_distortionTimeMax;
		}
	}
}

void OsgProject::stepManagment(float delta)
{
	_stepTimeElapsed += delta;
	if(_gameStep==0)
	{
		mRootNode->removeChildren(0,mRootNode->getNumChildren());
		mRootNode->addChild(_login->getNode());

		if(_stepTimeElapsed>=_step0TimeMax)
		{
			_gameStep = 1;
			_stepTimeElapsed=0;
			mRootNode->removeChildren(0,mRootNode->getNumChildren());
			_flashStep = 0;
			_flashTime = 0.0f;
			_flashValue = 0.0f;
		}
	}
	else if(_gameStep==1)
	{
		if(mRootNode->getNumChildren()<2)
		{
			mRootNode->addChild(_map->getNode());
#if CAVE == 0
			mRootNode->addChild(_snowGenerator->getNode());
#endif
			mRootNode->addChild(_skybox->createSkyBox());
			mRootNode->addChild(_lightSource1);
			mRootNode->addChild(_bombe);
			mRootNode->addChild(_hud->getHud());
			mRootNode->addChild(_arm->getArm());
		}

		if(_stepTimeElapsed>=_timeDistort)
		{
			_stepTimeElapsed = 0;
			_distortionTime = 0;
			_distortionStep = 0;
			_distortionValue = 0;
		}

		if(_bombeTimer>=_bombeTimeMax && _bombeExplose != true)
		{
			_bombManager->blowBomb();
			_bombeExplose = true;
			_flashStep = 0;
			_flashTime = 0.0f;
			_flashValue = 0.0f;
			removeBomb();
		}
		if(_joueur->isDead()==true)
		{
//			if(_bombGrabbed)
//				_flashTime += _flashTimeMax-delta*6;
			_gameStep = 2;
			mRootNode->removeChildren(0,mRootNode->getNumChildren());
		}
	}
	else if(_gameStep==2)
	{
		if(mRootNode->getNumChildren()<1)
		{
			mRootNode->addChild(_logout->getNode());
		}
	}
}
